/*

Frequency of use: 1 2 3 [4] 5 MEDIUM HIGH

Short:
    Command contains an action that you need to defer for some reason. We split 
the task into two commands (PrintHello and PrintWorld), and queue them up in 
Commands.

Long:
    In object-oriented programming, the command pattern is a design pattern in 
which an object is used to represent and encapsulate all the information needed 
to call a method at a later time. This information includes the method name, the 
object that owns the method and values for the method parameters.
Three terms always associated with the command pattern are client, invoker and 
receiver. The client instantiates the command object and provides the 
information required to call the method at a later time. The invoker decides 
when the method should be called. The receiver is an instance of the class that 
contains the method's code.
Using command objects makes it easier to construct general components that need 
to delegate, sequence or execute method calls at a time of their choosing 
without the need to know the owner of the method or the method parameters.

Information sources:
 - http://calumgrant.net/patterns/index.html
 - http://en.wikipedia.org/wiki/Command_pattern
 - http://www.dofactory.com/Patterns/Patterns.aspx
*/

#include <vector>
#include <algorithm>
#include <iostream>

class Command
{
public:
	virtual ~Command() { }
	virtual void execute()=0;
};

class PrintHello : public Command
{
public:
	void execute()
	{
		std::cout << "Hello ";
	}
};

class PrintWorld : public Command
{
public:
	void execute()
	{
		std::cout << "world!" << std::endl;
	}
};

class Commands
{
	std::vector<Command*> commands;
	struct ExecuteCommand
	{
		void operator()(Command * cmd)
		{
			cmd->execute();
		}
	};
public:
	void add_command(Command & cmd)
	{
		commands.push_back(&cmd);
	}
	void execute()
	{
		std::for_each(commands.begin(), commands.end(), ExecuteCommand());
	}
};

void hello_world(Commands & commands)
{
	commands.execute();
}

int main()
{
	Commands commands;
	PrintHello hello;
	PrintWorld world;
	commands.add_command(hello);
	commands.add_command(world);
	hello_world(commands);
	return 0;
}

